#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cerrno>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<sys/types.h>          /* See NOTES */
#include<sys/socket.h>
#include<memory>
#include<functional>
#include<vector>
#include<unistd.h>
#include<sys/wait.h>
#include<signal.h>
#include"ERR.hpp"

using namespace std;

namespace tcp_server
{

    const static uint16_t defport=1111;
    static const int backlog=32;
    
    using func_t =function<string(const string &)>;

    class TcpServer;
    class ThreadDate
    {
        public:
        ThreadDate(int fd,const string &ip,const uint16_t & port,TcpServer *t)
        :_sock(fd),_clientip(ip),_clientport(port),_current(t)
        {}
        public:
        int _sock;
        string _clientip;
        uint16_t _clientport;
        TcpServer *_current;



    };
    class TcpServer
    {
    public:
    TcpServer(func_t func,uint16_t port=defport)
        : _func(func) //消息
        ,_port(port)  //端口
        ,_quit(true)
    {   
    }

    //服务器初始化 套接字(socket)->sockaddr_in初始化  -> 绑定(bind)
    void InitServer_Start()
    {
        //(1)创建套接字
        _listensock=socket(AF_INET,SOCK_STREAM,0);  //(ipv4协议,面向连接可靠协议) 
        if(_listensock<0)
        {
            cerr<<"创建 socker 失败: "<<strerror(errno)<<endl;
            exit(SOCKER_ERR);
        }
        cout<<"创建 socker 成功:"<<_listensock<<endl;
        //（2）给指定服务器指明IP和port

        struct sockaddr_in local; //这个结构里主要有三部分信息: 地址类型, 端口号, IP地址.
        memset(&local,0,sizeof(local)); //清理local

        //2.1初始化local
        local.sin_family=AF_INET;    
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=htonl(INADDR_ANY);//bind本主机任意ip




        //3.把填充字段绑定到网络(bind)
        if(bind(_listensock,(struct sockaddr *)&local,sizeof(local))<0)
        {
            cerr<<"绑定失败: "<<strerror(errno)<<endl;
            exit(BIND_ERR); //返回错误码
        }
        cout<<"绑定 socker 成功:"<< _listensock <<endl;

        //监听
        if(listen(_listensock,backlog)<0)
        {
            cerr<<"listen socket error "<<endl;
            exit(LISTEN_ERR);
        }
        cout<<"监听 socker 成功:"<< _listensock <<endl;

    }

    void Start()
    {
        // signal(SIGCHLD,SIG_IGN); //对SIGCHLD信号进行忽略
        // signal(SIGCHLD,handler)  //设计回收子进程方法

        _quit=false;

        while(!_quit)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            
            int sock=accept(_listensock,(struct sockaddr*)&client,&len);
            if(sock<0) //直到获取成功
            {
                cerr<<"accept socket error "<<endl;
                continue;
            }
            string  clientip=inet_ntoa(client.sin_addr);//网络10进制转换成字节10进制
            uint16_t clientport=ntohs(client.sin_port); //网络转主机

            cout<<" accept success  "<<sock<<" from "<<_listensock<<", "
            <<clientip<<" - "<<clientport<<endl;

            //单进程调用
            // service(sock,clientip,clientport);

            //多进程调用
        //     pid_t id=fork();
        //     if(id <0)
        //     {
        //         close(sock);
        //         continue;
        //     }
        //     else if(id == 0)//子进程会继承父进程的文件描述符，
        //     {
        //         //关闭不需要的fd
        //         close(_listensock);
        //         if(fork()>0) exit(0); //子进程退出，孙子进程执行
        //         //最后孙子进程被进程回收
        //         service(sock,clientip,clientport); //不发生写时拷贝
        //         exit(0);
        //     }

        //     close(sock); //父进程不关闭会导致文件描述符资源泄漏

        //     pid_t ret=waitpid(id,nullptr,0);//阻塞状态,串行的 改成非阻塞
        //     //waitpid(id,nullptr,WNOHANG)
            // v3: 多线程 -- 原生多线程
            // 1. 要不要关闭不要的socket？？不能
            // 2. 要不要回收线程？如何回收？会不会阻塞？？
            pthread_t tid;
            ThreadDate *td = new ThreadDate(sock, clientip, clientport, this);
            pthread_create(&tid, nullptr, threadRuing, td);

            



        }
       
    }

    static void* threadRuing(void * args)
    {
        pthread_detach(pthread_self());

        ThreadDate *t =static_cast<ThreadDate*>(args);
        t->_current->service(t->_sock,t->_clientip,t->_clientport);
        delete t;
        return nullptr;

    }



    void service(int sock,const string &clientip,const uint16_t &clientport)
    {
        string who =clientip + "-"+ to_string(clientport);  //显示名称
        char buf[256];

        while(true)
        {
            ssize_t s= read(sock,buf,sizeof(buf)-1);
            if(s>0)
            {
                buf[s]=0;
                string res=_func(buf);
                cout<<who<<":"<<res<<endl;

                write(sock,res.c_str(),res.size());
            }
            else if(s==0)
            {
                close(sock);
                cout<<who<<"quite ..."<<endl;

            }
            else 
            {
                close(sock);
                cerr<<"read error: "<<strerror(errno)<<endl;
                break;

            }

        }

    }





    ~TcpServer()
    {   

    }




    private:
        
        uint16_t _port;
        int _listensock;
        bool _quit;
        func_t _func;


    };




};